<?php

/*
 * $Id: model.php 12 2010-11-28 20:02:53Z LEON $
 * $Author: LEON $
 * $LastChangedDate: 2010-11-28 20:02:53 +0000 (Sun, 28 Nov 2010) $
 * $Revision: 12 $
 */

namespace cmFly\system\data_model\orm;

use cmFly\data_model;

abstract class model extends base {

    protected $data = Array();

    public function __construct() {
	parent::__construct();
    }

    public static function create() {
	
    }

    public function save() {
	
    }

    public function reload() {
	
    }

    public function delete() {
	
    }

    public static function __callStatic($name, $arguments) {
	if (substr($name, 0, 7) == 'get_by_') {
	    $result = FALSE;
	    if (\method_exists(get_called_class(), $name)) {
		$result = \call_user_func_array(\get_called_class() . '::' . $name, $arguments);
	    } else {
		$by = explode('_', substr($name, 7));
		if (empty($by) || empty($by[0])) {
		    throw new data_model\exception(\get_called_class() . '::get_by method must be specify field or index!');
		}
		switch ($by[0]) {
		    case 'index':
			/**
			 * @todo реализовать выборку по индексам
			 */
			throw new data_model\exception(__CLASS__ . '::get_by_index method didn\'t realised!');
		    case 'primary':
			$by = static::get_table()->get_primary();
			if (!\is_array($by)) {
			    $by = Array($by);
			}
		    default:
			$select = static::get_select();
			$where = '';
			for ($i = 0; $i < count($by); $i+=2) {
			    $where.=$by[$i] . ' = ?';
			    if (isset($by[$i + 1])) {
				$where.=' ' . $by[$i + 1] . ' ';
			    }
			}
			$result = $select->where($where, $arguments);
		}
	    }
	    if (!$result) {
		throw new data_model\exception('Internal error! result in __callStatic is empty!');
	    }

	    $statement = $result->query();
	    $count = $statement->rowCount();
	    if (!$count) {
		throw new data_model\exception_not_found('Model data don\'t found for ' . \get_called_class() . '::' . $name);
	    }
	    if ($count > 1) {
		throw new data_model\exception('Model data owerflow for ' . \get_called_class() . '::' . $name);
	    }
	    $model = static::parse_row($statement);
	    return $model;
	}
	throw new data_model\exception('Call to undefined or protected function "' . \get_called_class() . '::' . $name . '"');
    }

    protected static function parse_row($statement) {
	$container = $statement->fetch();
	$model = new static();
	$model->data = $container[0]['values'];
	for ($i = 1; $i < count($container); $i++) {
	    $curr = &$container[$i];
	    $model->relations[$curr['user_data']]['data'] = $curr['values'];
	    if (!$curr['values']['id']) {
		$model->relations[$curr['user_data']]['not_found'] = true;
	    }
	}
	return $model;
    }

    public function __get($var_name) {
	if (\method_exists($this, $method = 'get_' . $var_name)) {
	    return $this->$method();
	}
	$table = static::get_table();
	$relations = $table->get_relations();
	$my_relation = &$relations[$var_name];

	if ($table->field_exists($var_name)) {
	    if (!isset($this->data[$var_name])) {
		//Lazy load field;
		//TODO: Реализовать примари индекс на несколько полей
		$primary = $table::get_primary();
		$fields = $table::get_fields();
		$container = $this->get_database()->get_constructor('select')
				->from($table->get_name())
				->fields(array($var_name => $fields[$var_name]))
				->where($primary . '=?', Array($this->data[$primary]))->query()->fetch();
		$this->data[$var_name] = $container[0]['values'][$var_name];
	    }
	    return $this->data[$var_name];
	}
	if ($class = $table->relation_class($var_name)) {
	    $relation = &$this->relations[$var_name];
	    if (!isset($this->relations[$var_name])) {
		//Lazy load;
		$q = $class::get_related($my_relation[$table::RELATION_CLASS_RELATION], Array($this->data[$my_relation[$table::RELATION_FIELD]]))->query()->fetch();
		$relation['data'] = $q[0]['values'];
	    }
	    if (isset($relation['not_found'])) {
		throw new data_model\exception_not_found('Not found relation data for "' . \get_called_class() . '::' . $var_name . '"');
	    }
	    //Lazy object create
	    if (!isset($relation['model'])) {
		$relation['model'] = $class::build_related($this, $my_relation[$table::RELATION_CLASS_RELATION], $relation['data']);
		unset($relation['data']);
	    }
	    return $this->relations[$var_name]['model'];
	}
    }

    public function __set($var_name, $var_value) {
	$this->data[$var_name] = $var_value;
    }

}